#ifndef ABSTRACTDRAWER_H
#define ABSTRACTDRAWER_H
#include "Glyph.h"
#include "GlyphCache.h"
#include <vector>

namespace FT
{
/**
 * @brief Class for simple text drawing. T must be derived from BaseGlyph.
 */
template <class T>
class AbstractDrawer
{
public:
    /**
     * @brief Creates AbstractDrawer with specified FontFace.
     * @param face FontFace to draw text with.
     */
    AbstractDrawer(FontFace &face):face(face)
    {
        cache = new GlyphCache<T>(face);
    }
    ~AbstractDrawer()
    {
        delete cache;
    }
    /**
     * @brief Set text for drawing.
     * @param text array of character codepoints
     * @param length length of text
     */
    void setText(ulong * text, uint length)
    {
        glyphs.clear();
        glyphsPos.clear();
        layoutGlyphs(text,length);
    }
    /**
     * @brief Draw text in specified position.
     * @param x x coordinate
     * @param y y coordinate
     */
    void draw(int x, int y)
    {
        for(uint i = 0; i < glyphs.size(); i++)
        {
            drawGlyph(glyphs[i],glyphsPos[i].x+x,glyphsPos[i].y+y);
        }
    }
protected:
    /**
     * @brief Draw seperate glyph in specified position.
     * @param glyph BaseGlyph to draw
     * @param x x coordinate
     * @param y y coordinate
     */
    virtual void drawGlyph(T* glyph, int x, int y) = 0;
    /**
     * @brief Layouts text(compute positions of glyphs).
     * @param text array of character codepoints
     * @param length length of text
     */
    void layoutGlyphs(ulong * text, uint length)
    {
        int penX = 0;
        int penY = 0;
        T* previos = nullptr;
        T* current = nullptr;
        for(uint i = 0; i < length; i++)
        {
            previos = current;
            current = cache->getGlyph(text[i]);
            if(face.hasKerning() && previos && current)
            {
                Point kerning = current->getKerning(*previos);
                penX += kerning.x;
            }
            glyphs.push_back(current);
            glyphsPos.push_back(Point(penX,penY-current->getHoriBearing().y));
            penX += current->getAdvance().x;
        }
    }
private:
    std::vector<T*> glyphs;
    std::vector<Point> glyphsPos;
    FontFace &face;
    GlyphCache<T> *cache;
};
}
#endif // ABSTRACTDRAWER_H
